package br.com.wepa.webapps.security;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.regex.Pattern;

public class SecurityProperties implements SecurityConstants {

	private static final String FILE_NAME = "security.properties";

	private static final String ACCESS_WHEN_NO_ROLE_FOUND = "control.security.access.when.no.role.found";

	private static final String AUTHENTICATION_KEY_ATTRIBUTE = "control.security.authentication.key.attribute";

	private static final String AUTHENTICATION_KEY_ATTRIBUTE_SCOPE = "control.security.authentication.key.attribute.scope";

	private static final String PERMISSIONS_ATTRIBUTE = "control.security.permissions.attribute";

	private static final String PERMISSIONS_ATTRIBUTE_SCOPE = "control.security.permissions.attribute.scope";

	private static final String SECURITY_MSG_ATTRIBUTE = "control.security.msg.attribute";

	private static final String SECURITY_MSG_ATTRIBUTE_SCOPE = "control.security.msg.attribute.scope";

	private static final String MSG_INVALID_AUTHENTICATION_KEY_STATE = "control.security.msg.invalid.auth.key.state";

	private static final String MSG_ACCESS_DENIED = "control.security.msg.access.denied";

	private static final String REDIRECT_INVALID_AUTHENTICATION_KEY_STATE = "control.security.invalid.auth.key.state.redirect";

	private static final String REDIRECT_ACCESS_DENIED = "control.security.access.denied.redirect";

	private static final String WHITE_LIST = "control.security.patterns.white.list";

	private static final String BLACK_LIST = "control.security.patterns.black.list";

	private static final String ENCRYPT_ALGORITHM = "control.security.encrypt.algorithm";

	private static final String PASSWORD_ENCRYPT_ALGORITHM = "control.security.password.encrypt.algorithm";

	private Properties properties;

	private Pattern whiteListPattern;

	private Pattern blackListPattern;

	private static SecurityProperties single;

	private SecurityProperties() {
		try {
			init();
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	public static SecurityProperties getInstance() {
		if (single == null) {
			single = new SecurityProperties();
		}
		return single;
	}

	public void init() throws Exception {
		loadPropertiesFile();
		loadWhiteList();
		loadBlackList();
	}

	@SuppressWarnings("unchecked")
	public void loadPropertiesFile() throws IOException, FileNotFoundException {
		properties = new Properties();
		String accessFile = this.getClass().getClassLoader().getResource(
				FILE_NAME).getPath();
		properties.load(new FileInputStream(accessFile));
	}

	private void loadWhiteList() {
		String list = getWhiteListProperty();

		if (getRedirectAccessDenied() != null
				&& !getRedirectAccessDenied().trim().equals("")) {
			if (list.equals("")) {
				list += "^" + getRedirectAccessDenied() + "$";
			} else {
				list += VALUE_SEPARATOR + "^" + getRedirectAccessDenied() + "$";
			}
		}
		if (getRedirectInvalidAuthenticationKeyState() != null
				&& !getRedirectInvalidAuthenticationKeyState().trim()
						.equals("")) {
			if (list.equals("")) {
				list += "^" + getRedirectInvalidAuthenticationKeyState() + "$";
			} else {
				list += VALUE_SEPARATOR + "^"+ getRedirectInvalidAuthenticationKeyState() + "$";
			}
		}
		whiteListPattern = compilePattern(list.split(VALUE_SEPARATOR));
	}

	private void loadBlackList() {
		blackListPattern = compilePattern(getBlackListProperty().split(
				VALUE_SEPARATOR));
	}

	private Pattern compilePattern(String[] array) {
		String patterns = "(";
		final String OR = "|";
		for (String urlPattern : array) {
			if (patterns.equals("(")) {
				patterns += urlPattern;
			} else {
				patterns += OR + urlPattern;
			}
		}
		patterns += ")";
		return Pattern.compile(patterns);
	}

	public boolean getAccessWhenNoRoleFound() {
		return Boolean.valueOf(properties.getProperty(
				ACCESS_WHEN_NO_ROLE_FOUND, ACCESS_WHEN_NO_ROLE_FOUND_DEFAULT));
	}

	public String getPermissionsAttribute() {
		return properties.getProperty(PERMISSIONS_ATTRIBUTE,
				PERMISSIONS_ATTRIBUTE_DEFAULT);
	}

	public String getPermissionsAttributeScope() {
		return properties.getProperty(PERMISSIONS_ATTRIBUTE_SCOPE,
				PERMISSIONS_ATTRIBUTE_SCOPE_DEFAULT);
	}

	public String getSecutiryMsgAttribute() {
		return properties.getProperty(SECURITY_MSG_ATTRIBUTE,
				SECURITY_MSG_ATTRIBUTE_DEFAULT);
	}

	public String getSecutiryMsgAttributeScope() {
		return properties.getProperty(SECURITY_MSG_ATTRIBUTE_SCOPE,
				SECURITY_MSG_ATTRIBUTE_SCOPE_DEFAULT);
	}

	public String getAuthenticationKeyAttribute() {
		return properties.getProperty(AUTHENTICATION_KEY_ATTRIBUTE,
				AUTHENTICATION_KEY_ATTRIBUTE_DEFAULT);
	}

	public String getAuthenticationKeyAttributeScope() {
		return properties.getProperty(AUTHENTICATION_KEY_ATTRIBUTE_SCOPE,
				AUTHENTICATION_KEY_ATTRIBUTE_SCOPE_DEFAULT);
	}

	public String getRedirectInvalidAuthenticationKeyState() {
		return properties.getProperty(
				REDIRECT_INVALID_AUTHENTICATION_KEY_STATE, null);
	}

	public String getRedirectAccessDenied() {
		return properties.getProperty(REDIRECT_ACCESS_DENIED, null);
	}

	public String getMsgInvalidAuthenticationKeyState() {
		return properties.getProperty(MSG_INVALID_AUTHENTICATION_KEY_STATE,
				MSG_INVALID_AUTHENTICATION_KEY_STATE_DEFAULT);
	}

	public String getMsgAccessDenied() {
		return properties.getProperty(MSG_ACCESS_DENIED,
				MSG_ACCESS_DENIED_DEFAULT);
	}

	public String getEncryptAlgorithm() {
		return properties.getProperty(ENCRYPT_ALGORITHM,
				ENCRYPT_ALGORITHM_DEFAULT);
	}

	public String getPasswordEncryptAlgorithm() {
		return properties.getProperty(PASSWORD_ENCRYPT_ALGORITHM,
				PASSWORD_ENCRYPT_ALGORITHM_DEFAULT);
	}

	public String getWhiteListProperty() {
		return properties.getProperty(WHITE_LIST, "");
	}

	public String getBlackListProperty() {
		return properties.getProperty(BLACK_LIST, "");
	}

	public Pattern getWhiteListPattern() {
		return whiteListPattern;
	}

	public Pattern getBlackListPattern() {
		return blackListPattern;
	}
	public boolean matchWhiteList(String a) {
		return getWhiteListPattern().matcher(a).find();
	}

}
